﻿package base.dao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.ReflectionUtils;

import base.helper.BaseHelper;
import base.support.Paged;

/**
 * 一个DAO层实现基类
 * 必须在事务保证及OpenSessionInView模式下才能正确运行
 * @author 
 * @param <T> 管理的对象类型
 */
public abstract class BaseDao<T> extends HibernateDaoSupport
{
	@SuppressWarnings("unchecked")
	private Class<T> entityClass = BaseHelper.getSuperClassGenricType(getClass());
	protected static Logger log = Logger.getLogger("dao");
	
	protected void setEntityClass(Class<T> entityClass)
	{
		this.entityClass = entityClass;
	}

	protected Class<T> getEntityClass()
	{
		return entityClass;
	}

	/**
     * 工具方法，获取符合条件的对象总数
     * @param propNames 属性名称集合
     * @param values 属性值集合
     * @return 符合条件的对象总数
     */
	protected int countUtil(String[] propNames, Object[] values)
    {
		Criteria criteria = getSession().createCriteria(getEntityClass());
		for (int i = 0; i < propNames.length && i < values.length; i++)
		{
			if (values[i] == null) criteria.add(Expression.isNull(propNames[i]));
			else criteria.add(Expression.eq(propNames[i], values[i]));
		}

		return (Integer) criteria.setProjection(Projections.rowCount()).uniqueResult();
    }
    
    /**
	 * 工具方法，通过属性集合获取对象
	 * 
	 * @param propNames 属性名称集合
	 * @param values 属性值集合
	 * @return 符合条件的对象
	 */
	@SuppressWarnings("unchecked")
	protected T getUtil(String[] propNames, Object[] values)
	{
		Criteria criteria = getSession().createCriteria(getEntityClass());
		// 过滤
		for (int i = 0; i < propNames.length && i < values.length; i++)
		{
			if (values[i] == null) criteria.add(Expression.isNull(propNames[i]));
			else criteria.add(Expression.eq(propNames[i], values[i]));
		}

		return (T) criteria.uniqueResult();
	}
	
	/**
	 * 工具方法，获取符合条件的对象集合，支持排序，支持分页
	 * 
	 * @param propNames 属性名称集合
	 * @param values 属性值集合
	 * @param orderBys 排序的属性名称集合
	 * @param ascOrDescs asc正序，desc倒序，其它值视为asc
	 * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
	 * @return 符合条件的对象集合
	 */
	@SuppressWarnings("unchecked")
	protected List<T> findUtil(String[] propNames, Object[] values, String[] orderBys, String[] ascOrDescs, int firstResult, int maxResults)
	{
		Criteria criteria = getSession().createCriteria(getEntityClass());
		// 分页
		if (firstResult != 0 || maxResults != Integer.MAX_VALUE)
		{
			criteria.setFirstResult(firstResult);
			criteria.setMaxResults(maxResults);
		}
		// 过滤
		for (int i = 0; i < propNames.length && i < values.length; i++)
		{
			if (values[i] == null) criteria.add(Expression.isNull(propNames[i]));
			else criteria.add(Expression.eq(propNames[i], values[i]));
		}
		// 排序
		for (int i = 0; i < orderBys.length && i < ascOrDescs.length; i++)
		{
			if (ascOrDescs[i].equals("asc"))
			{
				criteria.addOrder(Order.asc(orderBys[i]));
			}
			else
			{
				criteria.addOrder(Order.desc(orderBys[i]));
			}
		}

		return criteria.list();
	}
	
	/**
	 * 获得主键的名称
	 * @return 对象的主键属性名称
	 */
	protected String getIdName()
	{
		ClassMetadata meta = getSessionFactory().getClassMetadata(getEntityClass());
		String idName = meta.getIdentifierPropertyName();
		return idName;
	}
	
	/**
	 * 获得对象主键的值
	 * @param entity 处理的对象
	 * @return 主键的值
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public Serializable getId(T entity) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
	{
		return (Serializable) PropertyUtils.getProperty(entity, getIdName());
	}
	
	/**
	 * 清理hibernate缓冲区，提交所有修改
	 */
	public void flush()
	{
		this.getHibernateTemplate().flush();
	}
	
	/**
	 * 清空所有hibernate缓存
	 */
	public void clear()
	{
		this.getHibernateTemplate().clear();
	}
	
	/**
	 * 清除对象的缓存
	 * @param entity 被操作的对象
	 */
	public void evict(Object entity)
	{
		this.getHibernateTemplate().evict(entity);
	}
	
	/**
	 * 清除对象的缓存
	 * @param entitys 被操作的对象集合
	 */
	public void evict(List entitys)
	{
		for(Object entity : entitys)
		{
			this.getHibernateTemplate().evict(entity);
		}
	}

	/**
	 * 保存对象
	 * @param object 被操作的对象
	 * @return 数据库对象的主键
	 */
	public Serializable save(T object)
    {
    	return this.getHibernateTemplate().save(object);
    }

	/**
	 * 更新对象
	 * @param object 被操作的对象
	 */
    public void update(T object)
    {
    	this.getHibernateTemplate().update(object);
    }

    /**
     * 更新对象
     * @param object 被操作的对象
     */
    public void merge(T object)
    {
    	this.getHibernateTemplate().merge(object);
    }

	/**
	 * 删除对象
	 * @param object 被操作的对象
	 */
    public void remove(T object)
    {
    	this.getHibernateTemplate().delete(object);
    }
    
    /**
     * 通过主键ID删除对象
     * @param id 被操作对象的主键ID
     */
    public void removeById(Serializable id)
    {
    	this.getHibernateTemplate().delete(get(id));
    }

    /**
     * 删除所有给定的对象集合
     * @param entities 被操作的对象集合
     */
    public void removeAll(Collection<T> entities)
    {
    	this.getHibernateTemplate().deleteAll(entities);
    }
    
    /**
     * 对象的属性是否唯一
     * @param object 检查的对象
     * @param uniquePropNames 对象的属性集合
     * @return 如果唯一返回true，否则返回false
     */
    public boolean isUnique(T object, String... uniquePropNames)
    {
    	Criteria criteria = getSession().createCriteria(getEntityClass());
		criteria.setProjection(Projections.rowCount());
		try
		{
			for (String propName : uniquePropNames)
			{
				criteria.add(Expression.eq(propName, PropertyUtils.getProperty(object, propName)));
			}

			String idName = getIdName();
			Serializable id = getId(object);
			if (id != null)
				criteria.add(Expression.not(Expression.eq(idName, id)));
		} catch (Exception e)
		{
			ReflectionUtils.handleReflectionException(e);
		}
		return (Integer) criteria.uniqueResult() == 0;
    }
    
    /**
	 * 通过主键获取对象
	 * 
	 * @param id
	 *            对象的主键
	 * @return 符合条件的对象
	 */
	@SuppressWarnings("unchecked")
	public T load(Serializable id)
    {
    	return (T)this.getHibernateTemplate().load(getEntityClass(), id);
    }

	/**
     * 通过主键获取对象
     * @param id 对象的主键
     * @return 符合条件的对象
     */
	@SuppressWarnings("unchecked")
	public T get(Serializable id)
    {
		return (T) this.getHibernateTemplate().get(getEntityClass(), id);
    }
    
	/**
	 * 通过属性获取对象
	 * @param propName 属性名称
	 * @param value 属性值
	 * @return 符合条件的对象
	 */
    public T getBy(String propName, Object value)
	{
		return getBy(new String[] {propName}, new Object[] {value});
	}

    /**
	 * 通过属性集合获取对象
	 * @param propNames 属性名称集合
	 * @param values 属性值集合
	 * @return 符合条件的对象
     */
	public T getBy(String[] propNames, Object[] values)
	{
		return getUtil(propNames, values);
	}

	/**
	 * 获取对象的总数
	 */
	public int countAll()
	{
		return countBy(new String[] {}, new String[] {});
	}

	/**
	 * 获取所有对象集合
	 * @return 所有对象集合
	 */
	public List<T> findAll()
    {
		return findAll(0, Integer.MAX_VALUE);
    }
	
	/**
	 * 获取所有对象集合，支持分页
	 * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
	 * @return 符合条件的数据集合
	 */
	public List<T> findAll(int firstResult, int maxResults)
	{		
		return findAllSorted(new String[] {}, new String[] {}, firstResult, maxResults);
	}
	
	/**
	 * 获取所有对象集合，支持分页，返回分页后的数据
	 * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
	 * @return 分页后的数据
	 */
	public Paged<T> findAllPaged(int firstRow, int pageSize)
	{		
		List<T> result = findAll(firstRow, pageSize);
		int totalCount = countAll();
		return new Paged<T>(result, totalCount, firstRow, pageSize);
	}
	
	/**
	 * 获取所有对象集合，支持排序
	 * @param orderBy 排序的属性名称
	 * @param ascOrDesc asc正序，desc倒序，其它值视为asc
	 * @return 符合条件的数据集合
	 */
	public List<T> findAllSorted(String orderBy, String ascOrDesc)
	{
		return findAllSorted(orderBy, ascOrDesc, 0, Integer.MAX_VALUE);
	}
	
	/**
	 * 获取所有对象集合，支持排序，支持分页
	 * @param orderBy 排序的属性名称
	 * @param ascOrDesc asc正序，desc倒序，其它值视为asc
	 * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
	 * @return 符合条件的数据集合
	 */
	public List<T> findAllSorted(String orderBy, String ascOrDesc, int firstResult, int maxResults)
	{
		return findAllSorted(new String[] {orderBy}, new String[] {ascOrDesc}, firstResult, maxResults);
	}
	
	/**
	 * 获取所有对象集合，支持排序，支持分页，返回分页后的数据
	 * @param orderBy 排序的属性名称
	 * @param ascOrDesc asc正序，desc倒序，其它值视为asc
	 * @param firstRow 首条数据的位置
	 * @param pageSize 每页记录数
	 * @return 分页后的数据
	 */
	public Paged<T> findAllSortedPaged(String orderBy, String ascOrDesc, int firstRow, int pageSize)
	{
		List<T> result = findAllSorted(orderBy, ascOrDesc, firstRow, pageSize);
		int totalCount = countAll();
		return new Paged<T>(result, totalCount, firstRow, pageSize);
	}
    
	/**
	 * 获取所有对象集合，支持排序
	 * @param orderBys 排序的属性名称集合
	 * @param ascOrDescs asc正序，desc倒序，其它值视为asc
	 * @return 符合条件的数据集合
	 */
	public List<T> findAllSorted(String[] orderBys, String[] ascOrDescs)
	{
		return findAllSorted(orderBys, ascOrDescs, 0, Integer.MAX_VALUE);
	}	
	
	/**
	 * 获取所有对象集合，支持排序，支持分页
	 * @param orderBys 排序的属性名称集合
	 * @param ascOrDescs asc正序，desc倒序，其它值视为asc
	 * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
	 * @return 符合条件的数据集合
	 */
	public List<T> findAllSorted(String[] orderBys, String[] ascOrDescs, int firstResult, int maxResults)
	{
		return findBySorted(new String[] {}, new String[] {}, orderBys, ascOrDescs, firstResult, maxResults);
	}
	
	/**
	 * 获取所有对象集合，支持排序，支持分页，返回分页后的数据
	 * @param orderBys 排序的属性名称集合
	 * @param ascOrDescs asc正序，desc倒序，其它值视为asc
	 * @param firstRow 首条数据的位置
	 * @param pageSize 每页记录数
	 * @return 分页后的数据
	 */
	public Paged<T> findAllSortedPaged(String[] orderBys, String[] ascOrDescs, int firstRow, int pageSize)
	{
		List<T> result = findAllSorted(orderBys, ascOrDescs, firstRow, pageSize);
		int totalCount = countAll();
		return new Paged<T>(result, totalCount, firstRow, pageSize);
	}
	
    /**
     * 获取符合条件的对象总数
     * @param propName 属性名称
     * @param value 属性值
     * @return 符合条件的对象总数
     */
    public int countBy(String propName, Object value)
    {
    	return countBy(new String[] {propName}, new Object[] {value});
    }
    
    /**
     * 获取符合条件的对象总数
     * @param propNames 属性名称集合
     * @param values 属性值集合
     * @return 符合条件的对象总数
     */
    public int countBy(String[] propNames, Object[] values)
    {
    	return countUtil(propNames, values);
    }
    
    /**
     * 获取符合条件的对象集合
     * @param propName 属性名称
     * @param value 属性值
     * @return 符合条件的对象集合
     */
	public List<T> findBy(String propName, Object value)
	{		
		return findBy(propName, value, 0, Integer.MAX_VALUE);
	}
	
	/**
	 * 获取符合条件的对象集合，支持分页
     * @param propName 属性名称
     * @param value 属性值
     * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
     * @return 符合条件的对象集合
	 */
	public List<T> findBy(String propName, Object value, int firstResult, int maxResults)
	{
		return findBy(new String[] {propName}, new Object[] {value}, firstResult, maxResults);
	}
	
	/**
	 * 获取符合条件的对象集合，支持分页，返回分页后的数据
     * @param propName 属性名称
     * @param value 属性值
     * @param firstRow 首条数据的位置
	 * @param pageSize 每页记录数
     * @return 分页后的数据
	 */
	public Paged<T> findByPaged(String propName, Object value, int firstRow, int pageSize)
	{
		List<T> result = findBy(propName, value, firstRow, pageSize);
		int totalCount = countBy(propName, value);
		return new Paged<T>(result, totalCount, firstRow, pageSize);
	}

	/**
	 * 获取符合条件的对象集合
     * @param propNames 属性名称集合
     * @param values 属性值集合
     * @return 符合条件的对象集合
	 */
	public List<T> findBy(String[] propNames, Object[] values)
	{
		return this.findBy(propNames, values, 0, Integer.MAX_VALUE);
	}

	/**
	 * 获取符合条件的对象集合，支持分页
     * @param propNames 属性名称集合
     * @param values 属性值集合
     * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
     * @return 符合条件的对象集合
	 */
	public List<T> findBy(String[] propNames, Object[] values, int firstResult, int maxResults)
	{
		return findBySorted(propNames, values, new String[] {}, new String[] {}, firstResult, maxResults);
	}
	
	/**
	 * 获取符合条件的对象集合，支持分页，返回分页后的数据
     * @param propNames 属性名称集合
     * @param values 属性值集合
     * @param firstRow 首条数据的位置
	 * @param pageSize 每页记录数
     * @return 分页后的数据
	 */
	public Paged<T> findByPaged(String[] propNames, Object[] values, int firstRow, int pageSize)
	{
		List<T> result = findBy(propNames, values, firstRow, pageSize);
		int totalCount = countBy(propNames, values);
		return new Paged<T>(result, totalCount, firstRow, pageSize);
	}

	/**
	 * 获取符合条件的对象集合，支持排序
	 * @param propName 属性名称
     * @param value 属性值
     * @param orderBy 排序的属性名称
	 * @param ascOrDesc asc正序，desc倒序，其它值视为asc
	 * @return 符合条件的对象集合
	 */
	public List<T> findBySorted(String propName, Object value, String orderBy, String ascOrDesc)
	{
		return findBySorted(propName, value, orderBy, ascOrDesc, 0, Integer.MAX_VALUE);
	}

	/**
	 * 获取符合条件的对象集合，支持排序，支持分页
	 * @param propName 属性名称
     * @param value 属性值
     * @param orderBy 排序的属性名称
	 * @param ascOrDesc asc正序，desc倒序，其它值视为asc
	 * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
	 * @return 符合条件的对象集合
	 */
	public List<T> findBySorted(String propName, Object value, String orderBy, String ascOrDesc, int firstResult, int maxResults)
	{
		return findBySorted(new String[] {propName}, new Object[] {value}, new String[] {orderBy}, new String[] {ascOrDesc}, firstResult, maxResults);
	}
	
	/**
	 * 获取符合条件的对象集合，支持排序，支持分页，返回分页后的数据
	 * @param propName 属性名称
     * @param value 属性值
     * @param orderBy 排序的属性名称
	 * @param ascOrDesc asc正序，desc倒序，其它值视为asc
	 * @param firstRow 首条数据的位置
	 * @param pageSize 每页记录数
	 * @return 分页后的数据
	 */
	public Paged<T> findBySortedPaged(String propName, Object value, String orderBy, String ascOrDesc, int firstRow, int pageSize)
	{
		List<T> result = findBySorted(propName, value, orderBy, ascOrDesc, firstRow, pageSize);
		int totalCount = countBy(propName, value);
		return new Paged<T>(result, totalCount, firstRow, pageSize);
	}

	/**
	 * 获取符合条件的对象集合，支持排序
	 * @param propNames 属性名称集合
     * @param values 属性值集合
     * @param orderBys 排序的属性名称集合
	 * @param ascOrDescs asc正序，desc倒序，其它值视为asc
	 * @return 符合条件的对象集合
	 */
	public List<T> findBySorted(String[] propNames, Object[] values, String[] orderBys, String[] ascOrDescs)
	{
		return findBySorted(propNames, values, orderBys, ascOrDescs, 0, Integer.MAX_VALUE);
	}

	/**
	 * 获取符合条件的对象集合，支持排序，支持分页
	 * @param propNames 属性名称集合
     * @param values 属性值集合
     * @param orderBys 排序的属性名称集合
	 * @param ascOrDescs asc正序，desc倒序，其它值视为asc
	 * @param firstResult 首条数据的位置
	 * @param maxResults 返回数据的最大数
	 * @return 符合条件的对象集合
	 */
	public List<T> findBySorted(String[] propNames, Object[] values, String[] orderBys, String[] ascOrDescs, int firstResult, int maxResults)
	{
		return findUtil(propNames, values, orderBys, ascOrDescs, firstResult, maxResults);
	}
	
	/**
	 * 获取符合条件的对象集合，支持排序，支持分页，返回分页后的数据
	 * @param propNames 属性名称集合
     * @param values 属性值集合
     * @param orderBys 排序的属性名称集合
	 * @param ascOrDescs asc正序，desc倒序，其它值视为asc
	 * @param firstRow 首条数据的位置
	 * @param pageSize 每页记录数
	 * @return 分页后的数据
	 */
	public Paged<T> findBySortedPaged(String[] propNames, Object[] values, String[] orderBys, String[] ascOrDescs, int firstResult, int maxResults)
	{
		List<T> result = findBySorted(propNames, values, orderBys, ascOrDescs, firstResult, maxResults);
		int totalCount = countBy(propNames, values);
		return new Paged<T>(result, totalCount, firstResult, maxResults);
	}
}
